# -*- coding: utf8 -*-

__author__ = 'sergey'

import traceback
from time import sleep, time
import gobject
from datetime import datetime, timedelta
from threading import Thread, Event

class FindDupImages(Thread):
    """
    __init__ : args = ( app, ui, db_req, stats_req )
    """

    app = None
    ui = None
    db_req = None
    stats_req = None

    stop_event = None

    log = None

    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None, verbose=None):
        self.app, self.ui, self.db_req, self.stats_req = args
        self.stop_event = Event()
        Thread.__init__(self, group, target, name, args, kwargs, verbose)

    def run(self):
        from logger import get_file_logger
        self.log = get_file_logger("worker-FindDupImages")
        try:
            self.find_dupimages()
        except Exception as e:
            self.log.error(e)
            self.log.error(traceback.format_exc())
        return 0


    def match_func(self, model, iter, data):
        column, key = data # data is a tuple containing column number, key
        value = model.get_value(iter, column)
        return value == key

    def search(self, model, iter, func, data):
        while iter:
            if func(model, iter, data):
                return iter
            result = self.search(model, model.iter_children(iter), func, data)
            if result: return result
            iter = model.iter_next(iter)
        return None


    def add_image_to_treeview(self, image1, image2, image2image, store):

        img1_id_str = str(image2image["image1_id"])
        img2_id_str = str(image2image["image2_id"])

        img1_iter = self.search( store, store.iter_children(None), self.match_func, (0, img1_id_str,) )

        if not img1_iter:
            img1_iter = store.append( None, [ img1_id_str, None, image1["name"], None, None, ] )

        store.append( img1_iter, [
            None,
            img2_id_str,
            image2["name"],
            image2image["equal_proc"],
            image2image["quality_points"],
        ] )

        return


    def add_file_to_treeview(self, file1, file2, file2file, store):

        file1_id_str = str(file2file["image1_id"])
        file2_id_str = str(file2file["image2_id"])

        file1_iter = self.search( store, store.iter_children(None), self.match_func, (0, file1_id_str,) )

        if not file1_iter:
            file1_iter = store.append( None, [ file1_id_str, None, file1["name"], file2file["file1_count"], None, None, ] )

        store.append( file1_iter, [
            None,
            file2_id_str,
            file2["name"],
            file2file["file2_count"],
            file2file["equal_proc"],
            file2file["quality_points"],
            ] )

        return


    def find_dupimages(self):

        self.log.info("START")

        from images.vector import compare_vectors

        treeview2 = self.ui.get_object("treeview2")
        store_img = treeview2.get_model()

        store_img.clear()

        treeview4 = self.ui.get_object("treeview4")
        store_file = treeview4.get_model()

        store_file.clear()

        self.log.debug("Clean images dup table...")
        self.db_req.query("clean_image2image", ())
        self.db_req.query("clean_file2file", ())


        self.log.debug("Get images count...")
        t1 = datetime.now()
        images_count = self.db_req.query("get_images_count", ())
        t2 = datetime.now()
        self.log.debug("Got images count: %s, in %s" % (images_count, t2 - t1))

        processed = 0
        similar = 0

        gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_text,
            "Обработано: %d из %d (%0.3f%%); Найдено: %d (%0.3f%%)" % (
                processed, images_count, processed*100.0/images_count,
                similar, similar*100.0/images_count
                )
        )

        if not images_count:
            self.log.info("STOP")
            return 0

        offset = 0
        count = 20
        t_begin = time()

        self.log.debug(".. offset=%d, count=%d" % (offset, count,))

        req_id = self.db_req.query("get_images", (count, offset), no_return=True )
        t1 = datetime.now()
        while not self.db_req.has_result(req_id):
            if self.stop_event.isSet():
                break
            sleep(0.01)
        t2 = datetime.now()
        self.log.debug("Got images in %s" % (t2 - t1,))

        while not self.stop_event.isSet():
            item = self.db_req.get_result_row(req_id)

            self.log.debug("Item=%r" % item)
            # print("-- item: %r" % (item,))
            if item is None:
                if offset + count >= images_count:
                    break
                offset += count
                self.log.debug(".. offset=%d, count=%d" % (offset, count,))
                req_id = self.db_req.query("get_images", (count, offset), no_return=True )
                t1 = datetime.now()
                while not self.db_req.has_result(req_id):
                    if self.stop_event.isSet():
                        break
                    sleep(0.01)
                t2 = datetime.now()
                self.log.debug("Got images in %s" % (t2 - t1,))
                continue

            item_v10 = self.db_req.query("get_image_vectors10", (item["id"],))
            self.log.debug("Item vector 10=%r" % item_v10)

            gray_ids = ()

            self.log.debug("Get images gray like...")
            t1 = datetime.now()

            for v10 in item_v10:
                ids_req = self.db_req.query("get_similar_images10", (v10,), no_return=True )
                while not self.db_req.has_result(ids_req):
                    if self.stop_event.isSet():
                        break
                    sleep(0.01)
                #t2 = datetime.now()
                #self.log.debug("Got images gray like in %s" % (t2 - t1))

                #t1 = datetime.now()
                while True:
                    if self.stop_event.isSet():
                        break
                    ids_row = self.db_req.get_result_row(ids_req)
                    if ids_row is None:
                        break
                    if not gray_ids.count(ids_row['image_id']):
                        gray_ids += (ids_row['image_id'],)

            t2 = datetime.now()
            self.log.debug("Fetch images gray like: %s, in %s" % (len(gray_ids), t2 - t1))

            gray_count = len(gray_ids)


            item_v100 = None
            # self.log.debug("Item vector 100=%r" % item_v100)

            if not gray_count:
                processed += 1

            for img_id in gray_ids:

                if self.stop_event.isSet():
                    break

                processed += 1.0 / gray_count

                t_now = time()
                eta =  timedelta( seconds=(images_count - processed) / images_count * (t_now - t_begin))
                p = processed*1.0/images_count
                if p < 0:
                    p = 0
                if p > 1:
                    p = 1

                gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_fraction, p )
                gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_text,
                    "Обработано: %.3f из %d (%0.3f%%); Найдено: %d (%0.3f%%), Завершение через: %s" % (
                        processed, images_count, processed*100.0/images_count,
                        similar, similar*100.0/images_count, eta
                        )
                )

                # self.log.debug("Item gray id=%r" % img_id)

                if img_id == item["id"]:
                    # self.log.debug("Item gray id == item id")
                    continue

                # self.log.debug("Item gray compare with item...")
                if self.db_req.query("has_image2image", (item["id"], img_id,)):
                    # self.log.debug("Item gray compared with item")
                    continue

                img = self.db_req.query("get_image", (img_id,))

                # self.log.debug("Item gray get vectors 100")
                img_v100 = self.db_req.query("get_image_vectors100", (img_id,))

                if not item_v100:
                    item_v100 = self.db_req.query("get_image_vectors100", (item["id"],))

                # self.log.debug("Item gray vectors 100=%r" % img_v100)

                sim = 0
                comp = (0,)

                for j in range(len(item_v100)):
                    v100_1 = item_v100[j]["vector"]

                    for i in range(len(img_v100)):
                        v100_2 = img_v100[i]["vector"]

                        comp += ( compare_vectors(v100_1, v100_2, 0.1) , )
                        # self.log.debug("Item gray compared vs 100=%r" % (comp,))
                        if max(comp) >= 95:
                            sim += 1
                            break

                    if max(comp) >= 95:
                        break

                q_point = 0
                if sim:

                    self.log.debug("-- similar item=%r" % img)

                    if item["mime"] != img["mime"]:
                        if item["mime"] == "image/png":
                            q_point += 1
                        if img["mime"] == "image/png":
                            q_point -= 1
                    else:
                        if int(item["size"]) > int(img["size"]):
                            q_point += 1
                        else:
                            q_point -= 1

                    if int(item["width"])*int(item["height"]) > int(img["width"])*int(img["height"]):
                        q_point += 1
                    else:
                        q_point -= 1

                    if int(item["is_gray"]) > int(img["is_gray"]):
                        q_point += 1
                    else:
                        q_point -= 1


                    self.log.debug("Images compared & similar: %s, quality points: %s" % (max(comp), q_point,))
                    self.db_req.query("insert_image2image", (item["id"], img_id, max(comp), q_point,))


                    self.add_image_to_treeview( item, img, {
                        "image1_id":item["id"],
                        "image2_id":img["id"],
                        "equal_proc":max(comp),
                        "quality_points":q_point
                    }, store_img)

                    similar += 1


                    file2file = self.db_req.query("has_file2file", (item["file_id"], img["file_id"], ))
                    self.log.debug("Has File2File: %r" % (file2file,))
                    if not file2file:

                        file1_count = self.db_req.query("get_images_in_file_count", (item["file_id"],))
                        file2_count = self.db_req.query("get_images_in_file_count", (img["file_id"],))

                        self.log.debug("--: file 1 = %s, file 2 = %s" % (item["file_id"], img["file_id"],))
                        self.log.debug("--: images count 1 = %s, images count 2 = %s" % (file1_count, file2_count,))

                        self.db_req.query("insert_file2file", (
                            item["file_id"], img["file_id"], file1_count, file2_count,
                        ))
                    else:
                        if file2file["reverse"]:
                            q_point *= -1
                        self.log.debug("--: inc count and add quality points")
                        self.db_req.query("inc_file2file", ( file2file["id"], q_point,))


                    t_now = time()
                    eta =  timedelta( seconds=(images_count - processed) / images_count * (t_now - t_begin))
                    p = processed*1.0/images_count
                    if p < 0:
                        p = 0
                    if p > 1:
                        p = 1

                    gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_fraction, p )
                    gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_text,
                        "Обработано: %.3f из %d (%0.3f%%); Найдено: %d (%0.3f%%), Завершение через: %s" % (
                            processed, images_count, processed*100.0/images_count,
                            similar, similar*100.0/images_count, eta
                            )
                    )
                else:
                    # self.log.debug("Images compared: %s, quality points: %s" % (max(comp), q_point,))
                    self.db_req.query("insert_image2image", (item["id"], img_id, max(comp), q_point,))

                # self.log.debug("-- Next Item gray...")

            # processed += 1

            t_now = time()
            eta =  timedelta( seconds=(images_count - processed) / images_count * (t_now - t_begin))
            p = processed*1.0/images_count
            if p < 0:
                p = 0
            if p > 1:
                p = 1

            gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_fraction, p )
            gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_text,
                "Обработано: %.3f из %d (%0.3f%%); Найдено: %d (%0.3f%%), Завершение через: %s" % (
                    processed, images_count, processed*100.0/images_count,
                    similar, similar*100.0/images_count, eta
                    )
            )


        t_now = time()
        dt =  timedelta( seconds= (t_now - t_begin))
        p = processed*1.0/images_count
        if p < 0:
            p = 0
        if p > 1:
            p = 1

        gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_fraction, p )
        gobject.idle_add( self.ui.get_object("progressbar_nonuniq_images").set_text,
            "Обработано: %.3f из %d (%0.3f%%); Найдено: %d (%0.3f%%), Заняло: %s" % (
                processed, images_count, processed*100.0/images_count,
                similar, similar*100.0/images_count, dt
                )
        )

        self.log.info("STOP")

        self.stop_event.clear()

        return
